/*******************************************************
 * <p>Title: Velocity Pay Gateway Connector</p>
 *
 * <p>Description: A Java implementation of a connection
 *                 to the Velocity Pay service</p>
 *
 * <p>Copyright: Copyright (c) 2005</p>
 *
 * <p>Company: Velocity Pay</p>
 *
 * @version 1.0
 *******************************************************/
import java.net.*;
import java.io.*;


public class VPGatewayConnector
{
    private String m_szContentString = "";
    private String m_szReplyString = "";
    private String m_szLastExceptionReport = "";
    private boolean m_boLastConnectionAttemptSuccessful = false;

    /************************************************************************************
    * Method Name: VPGatewayConnector()
    *
    * Description: Class constructor
    *
    * Input Variables: N/A
    *
    * Output Variables: N/A
    *
    * Throws: N/A
    ************************************************************************************/
    public VPGatewayConnector()
    {
    }

    /************************************************************************************
    * Method Name: ClearGatewayParameters()
    *
    * Description: Clears the list of gateway input parameters
    *
    * Input Variables: N/A
    *
    * Output Variables: N/A
    *
    * Throws: N/A
    ************************************************************************************/
    public void ClearGatewayParameters()
    {
        m_szContentString = "";
    }

    /************************************************************************************
    * Method Name: AddGatewayParameter()
    *
    * Description: Adds a parameter to the list of gateway input paramters
    *
    * Input Variables: szParameterName - a "String" containing the name of the parameter
    *                  szParameterValue - a "String" containing the value of the parameter
    *
    * Output Variables: N/A
    *
    * Throws: N/A
    ************************************************************************************/
    public void AddGatewayParameter(String szParameterName, String szParameterValue)
    {
        m_szLastExceptionReport = "";

        // is this the first parameter in the list?
        if (m_szContentString.length() == 0)
        {
            // add the variable without a leading "&"
            try
            {
                m_szContentString = szParameterName + "=" +
                                    URLEncoder.encode(szParameterValue,
                    "US-ASCII");
            }
            catch (UnsupportedEncodingException uee)
            {
                m_szLastExceptionReport += uee + ". ";
            }
        }
        else
        {
            // add the variable with a leading "&"
            try
            {
                m_szContentString += "&" + szParameterName + "=" +
                                    URLEncoder.encode(szParameterValue,
                    "US-ASCII");
            }
            catch (UnsupportedEncodingException uee)
            {
                m_szLastExceptionReport += uee + ". ";
            }
        }
    }

    /************************************************************************************
    * Method Name: GetGatewayParameter()
    *
    * Description: Gets a named parameter from the reponse from the last connection to
    *              the Velocity Gateway
    *
    * Input Variables: szParameterName - a "String" containing the name of the parameter
    *
    * Output Variables: A "String" containing the parameter value
    *
    * Throws: An exception if the parameter wasn't found, or if the last connection to
    *         the Velocity Pay service was unsuccessful
    ************************************************************************************/
    public String GetGatewayParameter(String szParameterName) throws Exception
    {
        String szReturnString = "";
        boolean boFound = false;
        String aszSplitStrings[];
        int nNumberOfSplits;
        String szWorkingString;
        int nIndexOfEndToken;

        if (!m_boLastConnectionAttemptSuccessful)
        {
            throw new Exception("Did not previously connect to gateway");
        }
        else
        {
            // split the string using a regex (this is case insensitive)
            aszSplitStrings = m_szReplyString.split("(?i)\\b" + szParameterName + "\\b" +
                    "=");

            nNumberOfSplits = aszSplitStrings.length;

            // string should have been split in half
            if (nNumberOfSplits != 2)
            {
                throw new Exception("Parameter not found");
            }
            else
            {
                // the second split string is the one with the required data
                szWorkingString = aszSplitStrings[1];

                // get the position in this string of the variable end token
                nIndexOfEndToken = szWorkingString.indexOf("&");

                // was this token found?
                if (nIndexOfEndToken == -1)
                {
                    // token not found - must be the last variable in the list
                    szReturnString = szWorkingString;
                }
                else
                {
                    // the string needed is the substring of the current one,
                    // up to the variable end token
                    szReturnString = szWorkingString.substring(0, nIndexOfEndToken);
                }
            }
        }

        return (szReturnString);
    }

    /************************************************************************************
    * Method Name: GetLastError()
    *
    * Input Variables: N/A
    *
    * Output Variables: A "String" containing the last exception
    *
    * Throws: N/A
    ************************************************************************************/
    public String GetLastError()
    {
        return (m_szLastExceptionReport);
    }

    /************************************************************************************
    * Method Name: ConnectAndProcessPaymentRequest()
    *
    * Description: Connects to the Velocity Pay service to process a payment request
    *
    * Input Variables: aszServers - an array of "String"s containing a list of servers to
    *                               attempt connection to. Tries all the servers in the
    *                               list until it either connects, or all servers fail
    *
    * Output Variables: boolean - reports whether the connection attempt was successful
    *
    * Throws: An exception if the connection attempt was a failure
    ************************************************************************************/
    public String ConnectAndProcessPaymentRequest(String aszServers[]) throws Exception
    {
        boolean boConnectedToServer = false;
        int nCount = 0;
        String szCurrentServer;
        URL urlVelocityGateway;
        URLConnection cnGatewayConnection = null;
        DataOutputStream GatewayOutputStream;
        BufferedReader GatewayResponse;
        int nNumberOfServers;

        m_szLastExceptionReport = "";

        nNumberOfServers = aszServers.length;

        // no servers in list
        if (nNumberOfServers <= 0)
        {
            throw new Exception("No Servers specified");
        }

        // try and connect to one of the servers
        while (nCount < nNumberOfServers &&
               !boConnectedToServer)
        {
            szCurrentServer = aszServers[nCount];

            if (szCurrentServer.length() > 0)
            {
                try
                {
                    urlVelocityGateway = new URL(szCurrentServer);
                    cnGatewayConnection = urlVelocityGateway.openConnection();
                    // Let the run-time system (RTS) know that we want input.
                    cnGatewayConnection.setDoInput(true);
                    // Let the RTS know that we want to do output.
                    cnGatewayConnection.setDoOutput(true);
                    // No caching, we want the real thing.
                    cnGatewayConnection.setUseCaches(false);
                    // Specify the content type.
                    cnGatewayConnection.setRequestProperty ("Content-Type", "application/x-www-form-urlencoded");

                    GatewayOutputStream = new DataOutputStream (cnGatewayConnection.getOutputStream());

                    // write the content string to the buffer
                    GatewayOutputStream.writeBytes(m_szContentString);
                    GatewayOutputStream.flush ();
                    GatewayOutputStream.close ();

                    // get the gateway response
                    GatewayResponse = new BufferedReader(new InputStreamReader(cnGatewayConnection.
                        getInputStream()));

                    // save the gateway response for future parsing
                    m_szReplyString = GatewayResponse.readLine();

                    GatewayResponse.close();

                    // this connection was a success
                    boConnectedToServer = true;
                }
                catch (MalformedURLException mue)
                {
                    m_szLastExceptionReport += mue + ". ";
                }
                catch (IOException ioe)
                {
                    m_szLastExceptionReport += ioe + ". ";
                }
            }
            nCount++;
        }

        // save whether the last connection attempt was successful
        m_boLastConnectionAttemptSuccessful = boConnectedToServer;

        if (!boConnectedToServer)
        {
            throw new Exception("Connection attempt unsuccessful");
        }
        return (m_szReplyString);
    }
}
